package game.client;

import game.controller.GameController;
import game.controller.Unit.MilitaryUnit;
import game.util.GameLogger;
import game.packet.*;

import java.net.InetAddress;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
import java.io.IOException;
import java.util.ArrayList;

import lobby.packet.OpCode;
import lobby.packet.StartGamePacket;
import lobby.packet.JoinLobbyPacket;
import util.Messages;

/**
 * GameClientThread.java  Date Created: Oct 31, 2012
 *
 * Purpose: To receive any and all messages from the game server.
 *
 * Description: depending on the packet received call the appropriate controller method.
 *
 * @author Chrisb
 */
public class GameClientThread extends Thread {
    GameController controller;
    private byte[] incoming;
    private byte[] outgoing;
    private InetAddress gameAddress;
    private MulticastSocket socket;
    private DatagramPacket packet;
    private static final int GAME_PORT = 2024;

    private volatile Thread running;

    public GameClientThread(InetAddress address, GameController controller) {
        try {
            System.out.println("GameClientThread created");
            this.controller = controller;
            gameAddress = InetAddress.getByName(Messages.getString("game.server.address"));
            socket = new MulticastSocket(2022);
            socket.joinGroup(address);
            running = this;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void requestGameInfo(byte[] gameId, int nation) {
        try {
            System.out.println("GameClientThread:requestGameInfo");

            outgoing = new GenericPacket(GameOps.GAME_INFO.valueOf(), gameId, nation).getPacket();
            packet = new DatagramPacket(outgoing, outgoing.length, gameAddress, GAME_PORT);
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
            GameLogger.log("GameClientThread:requestGameInfo - " + e.getMessage());
        }
    }

    public void requestGameUsers(byte[] gameId, int nation) {
        try {
            System.out.println("GameClientThread:requestGameUsers");

            outgoing = new GenericPacket(GameOps.GAME_USERS.valueOf(), gameId, nation).getPacket();
            packet = new DatagramPacket(outgoing, outgoing.length, gameAddress, GAME_PORT);
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
            GameLogger.log("GameClientThread:requestGameUsers - " + e.getMessage());
        }
    }

    public void sendChatMessage(byte[] gameId, int fromNation, int toNation, String message) {
        try {
            System.out.println("GameClientThread:sendChatMessage");

            outgoing = new GameChatPacket(gameId, fromNation, toNation, message).getPacket();
            packet = new DatagramPacket(outgoing, outgoing.length, gameAddress, GAME_PORT);
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
            GameLogger.log("GameClientThread:sendChatMessage - " + e.getMessage());
        }
    }

    public void addUnitsToRegion(byte[] gameId, int regionIndex, int regionType, ArrayList<MilitaryUnit> units) {
        try {
            System.out.println("GameClientThread:addUnitsToRegion");
            outgoing = new GameAddUnitsPacket(gameId, regionIndex, regionType, units).getPacket();
            packet = new DatagramPacket(outgoing, outgoing.length, gameAddress, GAME_PORT);
            socket.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
            GameLogger.log("GameClientThread:addUnitsToRegion - " + e.getMessage());
        }
    }

    @Override
    public void run() {
        Thread thisThread = Thread.currentThread();
        while (running == thisThread) {
            try {
                incoming = new byte[256];
                packet = new DatagramPacket(incoming, incoming.length);
                socket.receive(packet);
                System.out.println("gameClient packet received");

                if (incoming[0] == OpCode.START_GAME.valueOf()) {
                    System.out.println("gameClient START_GAME");
                    StartGamePacket sgp = new StartGamePacket(incoming);
                    controller.createGame(sgp.getLobbyId(), sgp.getOptions(), sgp.getMSD(), sgp.getNation());
                } else if (incoming[0] == OpCode.JOIN.valueOf()) {
                    System.out.println("gameClient JOIN");
                    JoinLobbyPacket jlp = new JoinLobbyPacket(incoming);
                    controller.addUsers(jlp.getLobbyId(), jlp.getUsers());
                } else if (incoming[0] == GameOps.GAME_READY.valueOf()) {
                    System.out.println("gameClient makeGameReady");
                    GameReadyPacket grp = new GameReadyPacket(incoming);
                    controller.makeGameReady(grp.getGameId(), grp.getNation());
                } else if (incoming[0] == GameOps.ADD_UNITS.valueOf()) {
                    System.out.println("gameClient addUnits");
                    GameAddUnitsPacket aup = new GameAddUnitsPacket(incoming);
                    controller.processUnitPlacement(aup);
                } else if (incoming[0] == GameOps.UNITS_ADDED.valueOf()) {
                    System.out.println("gameClient unitsAdded");
                    AllUnitsAddedPacket aua = new AllUnitsAddedPacket(incoming);
                    controller.allUnitsAdded(aua.getNation());
                } else if (incoming[0] == GameOps.CHAT.valueOf()) {
                    GameChatPacket gcp = new GameChatPacket(incoming);
                    System.out.println("gameClient chat received from: " + gcp.getFromNation() + " to: " + gcp.getToNation());
                    controller.receiveChatMessage(gcp.getGameId(), gcp.getFromNation(), gcp.getToNation(), gcp.getChatMsg());
                } else if (incoming[0] == GameOps.GAME_NOT_FOUND.valueOf()) {
                    System.err.println("gameClient Game Not Found");
                    GameNotFoundPacket gnf = new GameNotFoundPacket(incoming);
                    gnf.getRequestedGameId();
                    gnf.getRequestedOpCode();
                    //todo resend?
                } else {
                    System.err.println("gameClient unknown packet received");
                }

            } catch (IOException e) {
                e.printStackTrace();
                GameLogger.log("Error occured in GameClientThread - " + e.getMessage());
            }
        }
    }

    public void stopThread() {
        running = null;
    }

}